﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using BOOL = System.Boolean;
using DWORD = System.UInt32;
using LPWSTR = System.String;
using NET_API_STATUS = System.UInt32;


namespace WebHelper.Helpers
{
    [Serializable]
    public class PathHelper : IDisposable
    {

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        internal struct USE_INFO_2
        {
            internal LPWSTR ui2_local;
            internal LPWSTR ui2_remote;
            internal LPWSTR ui2_password;
            internal DWORD ui2_status;
            internal DWORD ui2_asg_type;
            internal DWORD ui2_refcount;
            internal DWORD ui2_usecount;
            internal LPWSTR ui2_username;
            internal LPWSTR ui2_domainname;
        }

        [DllImport("NetApi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern NET_API_STATUS NetUseAdd(
            LPWSTR UncServerName,
            DWORD Level,
            ref USE_INFO_2 Buf,
            out DWORD ParmError);

        [DllImport("NetApi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern NET_API_STATUS NetUseDel(
            LPWSTR UncServerName,
            LPWSTR UseName,
            DWORD ForceCond);

        private bool disposed = false;



        private string f_FullPath = "";
        public string FullPath
        {
            get { return f_FullPath; }
        }

        public PathHelper(string fullpath)
        {
            this.f_FullPath = f_FullPath;
        }
        public PathHelper(string uNCPath, string domain, string user, string password)
        {
            this.f_FullPath = uNCPath;
            USE_INFO_2 useinfo = new USE_INFO_2();
            useinfo.ui2_remote = uNCPath;
            useinfo.ui2_username = user;
            useinfo.ui2_domainname = domain;
            useinfo.ui2_password = password;
            useinfo.ui2_asg_type = 0;
            useinfo.ui2_usecount = 1;
            uint paramErrorIndex;
            uint returncode = NetUseAdd(null, 2, ref useinfo, out paramErrorIndex);
        }
        public Exception Rename(string newName)
        {
            Exception error = null;
            string actualPath = this.GetPhysicalPath(this.f_FullPath);
            string parentDirectoryPath = new FileInfo(actualPath).Directory.FullName;
            try
            {
                Directory.Move(actualPath, parentDirectoryPath + "\\" + newName);
                this.f_FullPath = parentDirectoryPath +"\\" + newName;
            }
            catch (Exception e)
            {
                error = e;
            }
            return error;
        }

        public Exception CopyTo(string directoryPath, bool overWrite)
        {
            Exception error = null;
            string dir = this.GetPhysicalPath(directoryPath);
            string actualPath = this.GetPhysicalPath(this.f_FullPath);
            try
            {
                if (File.Exists(actualPath))
                {
                    Directory.CreateDirectory(dir);
                    FileInfo fi = new FileInfo(actualPath);
                    File.Copy(actualPath, dir + "\\" + fi.Name, overWrite);
                }
                else
                {
                    DirectoryInfo di = new DirectoryInfo(actualPath);
                    Directory.CreateDirectory(dir + "\\" + di.Name);
                    this.copyDirectoryContent(actualPath, dir + "\\" + di.Name, overWrite);
                }
            }
            catch (Exception er)
            {
                error = er;
            }
            return error;

        }

        public Exception CopyAs(string newFullPath, bool overWrite)
        {
            Exception error = null;
            string newP = this.GetPhysicalPath(newFullPath);
            string actualPath = this.GetPhysicalPath(this.f_FullPath);
            try
            {
                if (File.Exists(actualPath))
                {
                    FileInfo fi = new FileInfo(newP);
                    Directory.CreateDirectory(fi.Directory.FullName);
                    File.Copy(actualPath, newP, overWrite);
                }
                else
                {
                    Directory.CreateDirectory(newP);
                    this.copyDirectoryContent(actualPath, newP, overWrite);
                }
            }
            catch (Exception er)
            {
                error = er;
            }
            return error;

        }

        public Exception MoveTo(string directoryPath, bool overWrite)
        {
            Exception error = null;
            string dir = this.GetPhysicalPath(directoryPath);
            string actualPath = this.GetPhysicalPath(this.f_FullPath);

            try
            {
                if (File.Exists(actualPath))
                {
                    Directory.CreateDirectory(dir);
                    FileInfo fi = new FileInfo(actualPath);
                    File.Copy(actualPath, dir + "\\" + fi.Name, overWrite);
                    File.Delete(actualPath);
                    actualPath = dir + "\\" + fi.Name;
                }
                else
                {
                    DirectoryInfo di = new DirectoryInfo(actualPath);
                    Directory.CreateDirectory(dir + "\\" + di.Name);
                    this.copyDirectoryContent(actualPath, dir + "\\" + di.Name, overWrite);
                    Directory.Delete(actualPath);
                    actualPath = dir + "\\" + di.Name;
                }
            }
            catch (Exception er)
            {
                error = er;
            }
            return error;
        }

        public Exception MoveAs(string newFullPath, bool overWrite)
        {
            Exception error = null;
            string newP = this.GetPhysicalPath(newFullPath);
            string actualPath = this.GetPhysicalPath(this.f_FullPath);
            try
            {
                if (File.Exists(this.f_FullPath))
                {
                    FileInfo fi = new FileInfo(newP);
                    Directory.CreateDirectory(fi.Directory.FullName);
                    File.Copy(actualPath, newP, overWrite);
                    File.Delete(actualPath);
                    actualPath = newP;
                }
                else
                {
                    Directory.CreateDirectory(newP);
                    this.copyDirectoryContent(actualPath, newP, overWrite);
                    Directory.Delete(actualPath);
                    actualPath = newP;
                }
            }
            catch (Exception er)
            {
                error = er;
            }
            return error;

        }

        public Exception Delete()
        {

            Exception error = null;
            string actualPath = this.GetPhysicalPath(this.f_FullPath);
            try
            {
                if (File.Exists(actualPath))
                {
                    File.Delete(actualPath);
                }
                else
                {
                    Directory.Delete(actualPath);
                }
            }
            catch (Exception er)
            {
                error = er;
            }
            return error;
        }

        private void copyDirectoryContent(string source, string destination, bool overWrite)
        {
            DirectoryInfo di = new DirectoryInfo(source);
            FileInfo[] childsFilesInfo = di.GetFiles();
            for (int i = 0; i < childsFilesInfo.Length; i++)
            {
                childsFilesInfo[i].CopyTo(destination + "\\" + childsFilesInfo[i].Name, overWrite);
            }
            DirectoryInfo[] childsDirectoriesInfo = di.GetDirectories();
            for (int i = 0; i < childsDirectoriesInfo.Length; i++)
            {
                string s = destination + "\\" + childsDirectoriesInfo[i].Name;
                Directory.CreateDirectory(s);
                this.copyDirectoryContent(childsDirectoriesInfo[i].FullName, s, overWrite);
            }
        }

        public Exception NetUseDelete()
        {
            Exception error = null;
            try
            {
                uint returncode = NetUseDel(null, this.f_FullPath, 2);
            }
            catch (Exception er)
            {
                error = er;
            }
            return error;
        }

        public void Dispose()
        {
            if (!this.disposed)
            {
                NetUseDelete();
            }
            disposed = true;
            GC.SuppressFinalize(this);
        }

        private string GetPhysicalPath(string s)
        {
            if (s.StartsWith("http") || s.StartsWith("~") || s.StartsWith("../") || (s.StartsWith("/") && !s.StartsWith("//")))
            {
                return UrlHelper.GetPhysicalPath(s);
            }
            else
            {
                return s;
            }

        }

    }
}
